Spring Boot AOP系列之AOP原理介绍
序言:在本文中,jdk动态代理和cglib代理的核心原理,我都会一一讲到,看本文的时候可以结合着上文看,了解创建的过程,创建的生命周期,才能知晓原理
一、JDK动态代理原理
1、前言
其实大家看了上文的demo肯定会有所疑惑,为什么实现了一个InvocationHandler
接口就可以实现切面的植入了,就可以在写好的函数方法上面,植入我们的代码呢?是不是很神奇,惊不惊喜,意不意外。OK,废话不多说,下面跟着我的思路,走一遍源代码。
2、介绍
上文中提到了,Spring jdk动态代理最核心的一句话莫过于下面这句话
|
|
走进newProxyInstance
这个方法
|
|
getProxyClass0
核心方法片段如下:
|
|
proxyClassCache
是这样的
|
|
ProxyClassFactory
是Proxy
的一个静态内部类,实现了WeakCache
的内部接口BiFunction
的apply
方法,代码如下:
|
|
我们注意一下这行代码:
|
|
进去:
|
|
|
|
在启动项目的时候,虚拟机设置一下这个参数sun.misc.ProxyGenerator.saveGeneratedFiles
为true,就可以打印出代理对象的字节码文件。
PS:其实我们还有很多方法获取字节码文件,后文中介绍
OK,我们看下我们生成的字节码文件长什么样子:
我们可以清楚的看到生成的代理文件,实现了我们的自己需要的代理的接口QueryUserInfoBiz
,实现了SpringProxy
接口 ,继承了Proxy
类等。再来看看我们普通的一个方法,是如何被代理的。
insertUserInfoV5
这个方法被代理之后,被植入了一段代码,super.h.invoke
方法 , super表示Proxy这个夫类,h表示Proxy里面的一个属性,是InvocationHandler
类型的,回忆一下,我们在手动创建jdk动态代理的时候,是不是需要指定一个InvocationHandler
,这里就是起这个作用的,比如说在上个例子中,是我们自己写的MyInvocationHandler
类,但是在Spring中,我们没有指定这个handler
,那到底调用的是谁呢?
接上回:
在我们最开始用缓存创建那一段的时候,后面还有这样一段代码。这段代码的作用是让handler作为参数调用构造方法来获得代理类的实例
|
|
实际上,调用者是,一般而言,谁去准备创建proxy,谁一般就是这个handler,比如我们这里讲的aop里面,创建者就是JdkDynamicAopProxy
这个类,这个类他实现了InvocationHandler
接口,所以他被作为参数传进去了,自然而言,当代理类里面的方法被调用的时候,他的invoke方法就会被唤醒。
二、CGLib原理介绍
我们再来看看Cglib代理
先来看看Cglib手动创建的一个简单代码:
|
|
核心方法自然是create
方法,走进去看一下
|
|
createHelper
方法
|
|
调用了super.create
方法,核心代码如下:
|
|
然后看generate方法
|
|
再看generateClass
方法,这个就是生成代理文件的最核心逻辑了,先看Enhancer
里面的generateClass
方法,
|
|
这段就是生成字节码的核心逻辑,这段里面有很复杂的调用逻辑,我们这里不作详细介绍。
我们也有办法拿到CGLIB生成的代理文件,我这里不赘述,后面开一篇博客讲,这里面也挺麻烦的,当初我也找了很久。
OK,我们来看一下某一份生成好的代理字节码文件
这个代理类继承了我们被代理的类或者接口,然后实现了SpringProxy
、Advised
接口等, 首先当我们调用addOneCityV8
方法的时候,代理类会先去看CGLIB$CALLBACK_0
这个属性为不为空,这个是一个MethodIntercepter
类型的 ,如果为空就调用一个绑定方法,CGLIB$BIND_CALLBACKS
,它负责从一个叫做CGLIB$THREAD_CALLBACKS
的ThreadLocal对象中拿或者叫做CGLIB$STATIC_CALLBACKS
的Callback
数组中拿。拿到了之后就执行intercept
方法。
那么这里有个问题,回调类到底是如何选择的呢?
这里的处理逻辑和JDK动态代理类似,回调类基于一种,谁创建,谁负责的逻辑,已AOP创建动态代理为例,CglibAopProxy
这个类在创建代理的时候,会调用一个 getCallbacks
方法,在CglibAopProxy
中可以搜索到,代码如下:
|
|
根据摘取的部分片段可以得知,他是跟配置相关的,如果你没有作任何配置,那么系统一般首选DynamicAdvisedInterceptor
这个拦截器。也就是回调类就是DynamicAdvisedInterceptor
,会调用他里面的intercept
方法。
完毕。